#include "example.h"

ReturnCodeTypedef TestFcbIO(void)
{
  // Make sure FCB clock is enabled and HSI is used as system clock.
  SYS_EnableAPBClock(APB_MASK_FCB0);
  SYS_ClkSourceTypeDef clk_source = SYS_GetClkSource();
  SYS_SetClkSource(SYS_CLK_SOURCE_HSI);

  // Read the current IO configuration.
  FCB_IO_TypeDef io_cfg;
  FCB_ReadIOConfig(&io_cfg);

  // Then start to modify the configuration for each pin.
  // All pin IDs are predefined in the form of: LogicDevice_PinName_ID.
  FCB_PIN_TypeDef pin_cfg;

  // Set current strength.
  FCB_GetPinConfig(&io_cfg, AGRV2KL100_PIN_33_ID, &pin_cfg);
  FCB_PIN_SetCurrentStrength(&pin_cfg, FCB_PIN_CURRENT_4MA);
  FCB_SetPinConfig(&io_cfg, AGRV2KL100_PIN_33_ID, &pin_cfg);

  // Weakly pull down.
  FCB_GetPinConfig(&io_cfg, AGRV2KL100_PIN_29_ID, &pin_cfg);
  FCB_PIN_SetPullMode(&pin_cfg, FCB_PIN_PULL_DOWN);
  FCB_SetPinConfig(&io_cfg, AGRV2KL100_PIN_29_ID, &pin_cfg);

  // Weakly pull up.
  FCB_GetPinConfig(&io_cfg, AGRV2KL100_PIN_30_ID, &pin_cfg);
  FCB_PIN_SetPullMode(&pin_cfg, FCB_PIN_PULL_UP);
  FCB_SetPinConfig(&io_cfg, AGRV2KL100_PIN_30_ID, &pin_cfg);

  // Weakly keep the last value.
  FCB_GetPinConfig(&io_cfg, AGRV2KL100_PIN_46_ID, &pin_cfg);
  FCB_PIN_SetPullMode(&pin_cfg, FCB_PIN_PULL_KEEP);
  FCB_SetPinConfig(&io_cfg, AGRV2KL100_PIN_46_ID, &pin_cfg);

  // Enable open drain.
  FCB_GetPinConfig(&io_cfg, AGRV2KL100_PIN_47_ID, &pin_cfg);
  FCB_PIN_SetOpenDrain(&pin_cfg, true);
  FCB_SetPinConfig(&io_cfg, AGRV2KL100_PIN_47_ID, &pin_cfg);

  // Enable slow slew rate for an output to reduce noise.
  FCB_GetPinConfig(&io_cfg, AGRV2KL100_PIN_48_ID, &pin_cfg);
  FCB_PIN_SetSlowSlewRate(&pin_cfg, true);
  FCB_SetPinConfig(&io_cfg, AGRV2KL100_PIN_48_ID, &pin_cfg);

  // Write back the modified IO configuration to apply the changes.
  FCB_WriteIOConfig(&io_cfg);

  // Switch back the system clock.
  SYS_SetClkSource(clk_source);
  return RET_OK;
}

void TestFcb()
{
  bool success = true;
  if (MSG_UART) {
    while (UART_IsTxBusy(MSG_UART));
  }
  SYS_SwitchHSIClock();

  SYS_EnableAPBClock(APB_MASK_FCB0);
  SYS_EnableAHBClock(AHB_MASK_DMAC0);
  DMAC_Init();
  INT_EnableIRQ(FCB0_IRQn, MAX_IRQ_PRIORITY);

  // Read the default fpga_addr from option bytes. It can be a custom defined address, but must point to a configuration 
  // bit stream generated by Supra software.
  uint32_t fpga_addr   = RD_REG(FPGA_CONFIG_ADDR);
  uint32_t fpga_addr_n = RD_REG(FPGA_CONFIG_ADDR_N);
  if (fpga_addr == ~fpga_addr_n) {
    if (FCB_AutoConfigDma(fpga_addr, DMAC_CHANNEL7) != RET_OK) {
      success = false;
    }
  }

  SYS_SwitchPLLClock(board_hse_source());

  if (TestFcbIO() != RET_OK) {
    success = false;
  }

  printf("Fcb test %s!\n", success ? "passed" : "failed");
}

